package demo2

import (
	"fmt"
	"sync"
)

/*
	Go语言sync.Map（在并发环境中使用的map）
	 1. Go 语言中的 map 在并发情况下，只读是线程安全的，同时读写线程不安全。

*/

// TestDemo28 sync.Map 并发环境中使用
func TestDemo28() {
	// syncMap1 := make(map[int]int)

	// 并发代码
	// go func() {
	// 	// 不停对 map 写入
	// 	for {
	// 		syncMap1[1] = 1
	// 	}
	// }()

	// 并发代码
	// go func() {
	// 	// 不停对 map 进行读取
	// 	for {
	// 		_ = syncMap1[1]
	// 	}
	// }()

	// fatal error: concurrent map read and map write, 报错并发的 map 读写
	// for {
	// }

	/*
		sync.Map有以下特性：
			1. 无须初始化，直接声明即可。
			2. sync.Map 不能使用 map 的方式进行取值和设置等操作，而是使用 sync.Map 的方法进行调用。
					Store 表示存储，Load 表示获取，Delete 表示删除。
			3. 使用 Range 配合一个回调函数进行遍历操作，通过回调函数返回内部遍历出来的值。
			    Range 参数中的回调函数的返回值功能是：需要继续迭代遍历时，返回 true；终止迭代遍历时，返回 false。
	*/
	// sync.Map 不能使用 make 创建。
	var syncMap2 sync.Map

	// 保存键值对
	// sync.Map 将键和值以 interface{} 类型进行保存
	syncMap2.Store("name", "santiiny")
	syncMap2.Store("address", "luoyang")
	syncMap2.Store("price", 100)

	// 从 sync.Map 取值
	fmt.Println(syncMap2.Load("name"))

	// 删除键值对
	syncMap2.Delete("no")

	// for range 遍历 sync.Map
	// Range() 方法可以遍历 sync.Map，遍历需要提供一个匿名函数，参数为 k、v，类型为 interface{}，
	// 每次 Range() 在遍历一个元素时，都会调用这个匿名函数把结果返回。
	syncMap2.Range(func(v, k interface{}) bool {
		fmt.Println("iterate: ", k, v)
		return true
	})

	// tips: sync.Map 没有提供获取 map 数量的方法，替代方法是获取时遍历自行计算数量。
	//   sync.Map 为了保证并发安全有一些性能损失，因此在非并发情况下，使用 map 相比使用 sync.Map 会有更好的性能。
}
